/*
PearReview - The peer review assistant.
Copyright (C) 2009  Dimitrij Pankratz, Anton Musichin
http://www.pearreview.com, info@pearreview.com

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package com.pearreview.ui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.Serializable;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.JCheckBox;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ActionMapUIResource;

public class TriStateCheckBox extends JCheckBox {
	
	private static final long serialVersionUID = 1535066482592115228L;
	public static enum State {CHECKED, UNCHECKED, PARTIAL};

	private final TristateDecorator model;
	public TriStateCheckBox(){
		
		super.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				grabFocus();
				model.nextState();
				
				fireActionPerformed(new ActionEvent(TriStateCheckBox.this, 
						e.getID(), 
						null));
			}
		});
		
		ActionMap map = new ActionMapUIResource();
		map.put("pressed", new AbstractAction() {
			private static final long serialVersionUID = -2755748844190947493L;

			public void actionPerformed(ActionEvent e) {
				grabFocus();
				model.nextState();
				fireActionPerformed(new ActionEvent(TriStateCheckBox.this, 
						e.getID(), 
						null));
			}
		});
		map.put("released", null);
		SwingUtilities.replaceUIActionMap(this, map);
		
		
		model = new TristateDecorator(getModel());
		setModel(model);
		setState(State.UNCHECKED);
	}

	@Override
	public boolean isSelected() {
		return model.isSelected();
	}
	  
	public void setState(State state) { 
		model.setState(state);
	}
	  
	public State getState() { 
		return model.getState(); 
	}
	
	@Override
	public void setSelected(boolean b) {
		if (b) {
			setState(State.CHECKED);
		} else {
			setState(State.UNCHECKED);
		}
	}
	
	private class TristateDecorator implements ButtonModel, Serializable {
		private static final long serialVersionUID = -5738441863890802633L;
		private final ButtonModel checkBoxModel;
		private State currentState;
		private TristateDecorator(ButtonModel model) {
			this.checkBoxModel = model;
		}
		private void setState(State state) {
			switch(state) {
			case UNCHECKED:
				checkBoxModel.setArmed(false);
				setPressed(false);
				setSelected(false);
				break;
			case CHECKED:
				checkBoxModel.setArmed(false);
				setPressed(false);
				setSelected(true);
				break;
			case PARTIAL:
				checkBoxModel.setArmed(true);
				setPressed(true);
				setSelected(true);
			}
			currentState = state;
		}
		
		private State getState() {
			return currentState;
		}
		
		private void nextState() {
			switch(currentState) {
			case CHECKED:
				setState(State.UNCHECKED);
				break;
			case PARTIAL:
			case UNCHECKED:
				setState(State.CHECKED);
				break;
			}
		}
		@Override
		public void setArmed(boolean b) {
		}
		@Override
		public void setEnabled(boolean b) {
			setFocusable(b);
			checkBoxModel.setEnabled(b);
		}
		@Override
		public boolean isArmed() { 
			return checkBoxModel.isArmed(); 
		}
		@Override
		public boolean isSelected() {
			switch(getState()) {
			case PARTIAL:
			case CHECKED:
				return true;
			case UNCHECKED:
				return false;
			}
			
			return false;
		}
		@Override
		public boolean isEnabled() { 
			return checkBoxModel.isEnabled(); 
		}
		@Override
		public boolean isPressed() { 
			return checkBoxModel.isPressed(); 
		}
		@Override
		public boolean isRollover() { 
			return checkBoxModel.isRollover(); 
		}
		@Override
		public void setSelected(boolean b) { 
			checkBoxModel.setSelected(b);
		}
		@Override
		public void setPressed(boolean b) { 
			checkBoxModel.setPressed(b); 
		}
		@Override
		public void setRollover(boolean b) { 
			checkBoxModel.setRollover(b); 
		}
		@Override
		public void setMnemonic(int key) { 
			checkBoxModel.setMnemonic(key); 
		}
		@Override
		public int getMnemonic() { return 
			checkBoxModel.getMnemonic(); 
		}
		@Override
		public void setActionCommand(String s) {
			checkBoxModel.setActionCommand(s);
		}
		@Override
		public String getActionCommand() {
			return checkBoxModel.getActionCommand();
		}
		@Override
		public void setGroup(ButtonGroup group) {
			checkBoxModel.setGroup(group);
		}
		@Override
		public void addActionListener(ActionListener l) {
			checkBoxModel.addActionListener(l);
		}
		@Override
		public void removeActionListener(ActionListener l) {
			checkBoxModel.removeActionListener(l);
		}
		@Override
		public void addItemListener(ItemListener l) {
			checkBoxModel.addItemListener(l);
		}
		@Override
		public void removeItemListener(ItemListener l) {
			checkBoxModel.removeItemListener(l);
		}
		@Override
		public void addChangeListener(ChangeListener l) {
			checkBoxModel.addChangeListener(l);
		}
		@Override
		public void removeChangeListener(ChangeListener l) {
			checkBoxModel.removeChangeListener(l);
		}
		@Override
		public Object[] getSelectedObjects() {
			return checkBoxModel.getSelectedObjects();
		}
	}
}
